package cn.aiweiyi.qingjing.coupon.gateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

/**
 * @author 青衿
 * @Date 2020/11/12 20:57
 **/

/**
 * 优惠券的自定义过滤器
 * 顶层父类
 */
public abstract class AbstractZuulFilter extends ZuulFilter {


    //用于在过滤器之间共享数据,RequestContext父类是ConcurrentHashMap,因此
    //存储的K-V是线程安全的,另外,该类还是用ThreadLocal确保每个请求线程各自一份

    RequestContext context;
    //该Key用于context中存储布尔值,过滤器要不要执行???
    //当过滤器失败不能继续运行,就以该Key保存一个false
    static final String NEXT = "continue";


//    @Override
//    public String filterType() {
//        return null;
//    }
//
//    @Override
//    public int filterOrder() {
//        return 0;
//    }

    /**
     * 该方法返回值,用来决定要不要执行过滤逻辑,即run()方法
     *
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext context = RequestContext.getCurrentContext();
        return (boolean) context.getOrDefault(NEXT, true);
    }

    @Override
    public Object run() throws ZuulException {
        context = RequestContext.getCurrentContext();
        return cRun();
    }

    //该方法设置抽象,留给本项目的各个具体Filter子类重写,这是一个扩展点
    protected abstract Object cRun();

    //该方法留给子类过滤器使用,当过滤器因为某些原因不需要继续执行,
    //子类调用该方法让过滤器停止执行,并返回状态和提示信息
    Object fail(int code, String msg) {
        context.set(NEXT, false);
        context.setSendZuulResponse(false);
        context.getResponse().setContentType("text/html;charset=UTF-8");
        context.setResponseStatusCode(code);
        context.setResponseBody(String.format("{\"result\":\"%s!\"}", msg));
        return null;
    }

    //该方法留给子类过滤器使用,当过滤器逻辑执行成功,需要放行继续执行
    //过滤器链的下一个过滤器时,调用该方法。
    Object success() {
        context.set(NEXT, true);
        return null;
    }
}
